#include "stdafx.h"
#include "parameter_editor.h"


QModelIndex getIndex(const QModelIndex &old_index, typeCol_t type){
	QModelIndex new_index(old_index);
	new_index.c = type;
	return new_index;
}

PropertiesItem::PropertiesItem(const QVector<QVariant> &data, PropertiesItem *parent){
	parentItem = parent;
	itemData = data;
}

PropertiesItem::~PropertiesItem(){
	qDeleteAll(childItems);
}

PropertiesItem *PropertiesItem::child(int number){
	return childItems.value(number);
}

int PropertiesItem::childCount() const{
	return childItems.count();
}

int PropertiesItem::childNumber() const{
	if (parentItem)
		return parentItem->childItems.indexOf(const_cast<PropertiesItem*>(this));
	return 0;
}

int PropertiesItem::columnCount() const{
	return itemData.count();
}

QVariant PropertiesItem::data(int column) const{
	return itemData.value(column);
}

bool PropertiesItem::insertChildren(int position, int count, int columns){
	if (position < 0 || position > childItems.size())
		return false;
	for (int row = 0; row < count; ++row) {
		QVector<QVariant> data(columns);
		PropertiesItem *item = new PropertiesItem(data, this);
		childItems.insert(position, item);
	}

	return true;
}

PropertiesItem *PropertiesItem::parent(){
	return parentItem;
}

bool PropertiesItem::setData(int column, const QVariant &value){
	if (column < 0 || column >= itemData.size())
		return false;
	itemData[column] = value;
	return true;
}

PropertiesModel::PropertiesModel(QObject *parent)
	: QAbstractItemModel(parent)
{
	QStringList headers;
	headers << "Name" << "Value"<< "Unit"<< "Type" << "State" << "Description" << "Items";
		QVector<QVariant> rootData;
	foreach (QString header, headers)
		rootData << header;

	rootItem = new PropertiesItem(rootData);
}

PropertiesModel::~PropertiesModel(){
	delete rootItem;
}

void PropertiesModel::addItem(const QString &name, const QVariant &value, const QString &units, const int &type,
	const int &state, const QString &description, const bool &child, const bool &expanded) const{
	PropertiesItem *parent;
	if (child){
		parent = rootItem->child(rootItem->childCount() - 1);
	}else parent = rootItem;

	parent->insertChildren(parent->childCount(), 1, rootItem->columnCount());
	parent->child(parent->childCount() - 1)->setData(0, name);
	if (type == 0){
		if(value == true) parent->child(parent->childCount() - 1)->setData(1, "Yes");
		else parent->child(parent->childCount() - 1)->setData(1, "No");
	}else if (type == 4){
		QStringList list = value.toString().split(";");
		parent->child(parent->childCount() - 1)->setData(1, list[list[0].toInt() + 1]);
		parent->child(parent->childCount() - 1)->setData(6, value);
	}else if (type == 5){
		QStringList list = value.toString().split("/").back().split(";");
		QString row_count = QString::number(list.count());
		if (list.count() == 1 && list[0] == "") row_count = "0";
		parent->child(parent->childCount() - 1)->setData(1, "count: " + row_count);
		parent->child(parent->childCount() - 1)->setData(6, value);
	}else parent->child(parent->childCount() - 1)->setData(1, value);

	parent->child(parent->childCount() - 1)->setData(2, units);
	parent->child(parent->childCount() - 1)->setData(3, type);
	parent->child(parent->childCount() - 1)->setData(4, state);
	parent->child(parent->childCount() - 1)->setData(5, description);

	parent->child(parent->childCount() - 1)->setData(7, expanded);


}

int PropertiesModel::columnCount(const QModelIndex & /* parent */) const{
	return rootItem->columnCount();
}

QVariant PropertiesModel::data(const QModelIndex &index, int role) const{
	if (!index.isValid())
		return QVariant();
	if (role != Qt::DisplayRole && role != Qt::EditRole)
		return QVariant();
	if (role == Qt::FontRole){
		QFont boldFont;
		boldFont.setBold(true);
		return boldFont;
	}
	PropertiesItem *item = getItem(index);
	return item->data(index.column());
}

Qt::ItemFlags PropertiesModel::flags(const QModelIndex &index) const{
	if (!index.isValid())
		return 0;
	return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}

PropertiesItem *PropertiesModel::getItem(const QModelIndex &index) const{
	if (index.isValid()) {
		PropertiesItem *item = static_cast<PropertiesItem*>(index.internalPointer());
		if (item) return item;
	}
	return rootItem;
}

QVariant PropertiesModel::headerData(int section, Qt::Orientation orientation,
	int role) const{
	if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
		return rootItem->data(section);

	return QVariant();
}

QModelIndex PropertiesModel::index(int row, int column, const QModelIndex &parent) const{
	
	if (parent.isValid() && parent.column() != 0)
		return QModelIndex();

	PropertiesItem *parentItem = getItem(parent);

	PropertiesItem *childItem = parentItem->child(row);
	if (childItem)
		return createIndex(row, column, childItem);
	else
		return QModelIndex();
}

QModelIndex PropertiesModel::parent(const QModelIndex &index) const{

	if (!index.isValid())
		return QModelIndex();

	PropertiesItem *childItem = getItem(index);
	PropertiesItem *parentItem = childItem->parent();

	if (parentItem == rootItem)
		return QModelIndex();
	return createIndex(parentItem->childNumber(), 0, parentItem);
}


int PropertiesModel::rowCount(const QModelIndex &parent) const{
	PropertiesItem *parentItem = getItem(parent);
	return parentItem->childCount();
}

bool PropertiesModel::setData(const QModelIndex &index, const QVariant &value,
	int role)
{
	if (role != Qt::EditRole)
		return false;
	PropertiesItem *item = getItem(index);
	bool result = item->setData(index.column(), value);
	if (result)
		emit dataChanged(index, index);
	return result;
}

int PropertiesModel::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight){
	if (topLeft.r == bottomRight.r && topLeft.c ==1 && bottomRight.c == 1){
		QVariant v;
		if (getIndex(topLeft, TYPE).data().toInt() == 0){
			if(topLeft.data() == "Yes") v = true; else v = false;
		}else if (getIndex(topLeft, TYPE).data().toInt() == 4){
			QString cur_item = topLeft.data(Qt::DisplayRole).toString();
			QStringList list = getIndex(topLeft, DATA).data(Qt::DisplayRole).toString().split(";");
			v = getComboboxDataString(cur_item, list);
		}else v = topLeft.data();

		emit ItemChanged(topLeft.parent().r, topLeft.r, v);
	}
	return 0;
}

void PropertiesModel::changeData(const int &parent_row, const int &row, const QVariant &value){
	int type;
	if(parent_row == -1) type = rootItem->child(row)->data(3).toInt();
	else type = rootItem->child(parent_row)->child(row)->data(3).toInt();
	QVariant v;
	if (type == 0){
		if(value == true) v = "Yes"; else v = "No";
	}else if (type == 4){
		QStringList list = value.toString().split(";");
		v = list[list[0].toInt() + 1];
	}else v = value;

	if(parent_row == -1) rootItem->child(row)->setData(1, v);
	else rootItem->child(parent_row)->child(row)->setData(1, v);

	if (type == 4){
		if(parent_row == -1) rootItem->child(row)->setData(6, value);
		else rootItem->child(parent_row)->child(row)->setData(6, value);
	}
	emit update();
}


void PropertiesModel::setDescription(QLabel *descr_label, QModelIndex sel_index){
	descr_label->setText("description:\n" + getIndex(sel_index, DESCR).data().toString());
}

QStringList PropertiesModel::getAllParameters(){
	QStringList list;
	int i = 0;
	QString name, value, unit;
	while (index(i,0).isValid()){
		name = getIndex(index(i,0), NAME).data().toString();
		if (getIndex(index(i, 0), TYPE).data().toInt() == 5)
			value = getIndex(index(i,0), DATA).data().toString();
		else
			value = getIndex(index(i,0), VALUE).data().toString();
		unit = getIndex(index(i,0), UNIT).data().toString();
		list.push_back(name + " ; " + value + " ; " + unit);
		int j = 0;
		while (index(i,0).child(j, 0).isValid()){
			name = getIndex(index(i,0).child(j, 0), NAME).data().toString();
			if (getIndex(index(i,0).child(j, 0), TYPE).data().toInt() == 5)
				value = getIndex(index(i,0).child(j, 0), DATA).data().toString();
			else
				value = getIndex(index(i,0).child(j, 0), VALUE).data().toString();
			unit = getIndex(index(i,0).child(j, 0), UNIT).data().toString();
			list.push_back(name + " ; " + value + " ; " + unit);
			j++;
		}
		i++;
	}
	return list;
}

QString PropertiesModel::getParameter(const QString &name){
    QModelIndex index = this->match(this->index(0, 0), Qt::DisplayRole, QVariant(name), 1,
        Qt::MatchFlags(Qt::MatchRecursive | Qt::MatchFixedString | Qt::MatchStartsWith))[0];
    QString data;
    if(getIndex(index, TYPE).data() == 5){
        data = getIndex(index, DATA).data().toString();
    }else{
        data = getIndex(index, VALUE).data().toString();
    }
    return data;
}

void PropertiesModel::setAllParameters(const QStringList &list){
	for (int i = 0; i < list.count(); i++){
		QStringList parameter_data = list[i].split(" ; ");
		QModelIndex index = this->match(this->index(0, 0), Qt::DisplayRole, QVariant(parameter_data[0]), 1,
			Qt::MatchFlags(Qt::MatchRecursive | Qt::MatchFixedString | Qt::MatchStartsWith))[0];
		if (getIndex(index, TYPE).data().toInt() == 5){
			QStringList list = parameter_data[1].split("/").back().split(";");
			QString row_count = QString::number(list.count());
			if (list.count() == 1 && list[0] == "") row_count = "0";
			this->setData(getIndex(index, VALUE), "count: " + row_count);
			this->setData(getIndex(index, DATA), parameter_data[1]);
		}else
			this->setData(getIndex(index, VALUE), parameter_data[1]);
		this->setData(getIndex(index, UNIT), parameter_data[2]);
	}
	
}

QWidget *Delegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const{
	if (index.column() == 0) {
		QLabel *label = new QLabel(parent);
		return label;
	}else if (index.column() == 1) {
		int type = getIndex(index, TYPE).data(Qt::DisplayRole).toInt();
		QVariant val = index.model()->data(index, Qt::DisplayRole);
		if (type == 0){
			QComboBox *editor = new QComboBox(parent);
			editor->addItem("Yes");
			editor->addItem("No");
			return editor;
		} else if (type == 1){
			QDoubleSpinBox *spinbox = new QDoubleSpinBox(parent);
			spinbox->setMaximum(1e6);
			spinbox->setMinimum(-1e6);
			spinbox->setValue(val.toDouble());
			return spinbox;
		} else if (type == 2){
			QLineEdit *editor = new QLineEdit(parent);
			editor->setText(index.model()->data(index, Qt::DisplayRole).toString());
			return editor;
		} else if (type == 4){
			QStringList list = getIndex(index, DATA).data(Qt::DisplayRole).toString().split(";");
			QComboBox *editor = new QComboBox(parent);
			for(int i = 1; i < list.count(); i++)
				editor->addItem(list[i]);
			editor->setCurrentIndex(list[0].toInt());
			return editor;
		}
	}else{	
		if(getIndex(index, TYPE).data().toInt() != 5){
			QComboBox *editor = new QComboBox(parent);
			QString currentText = index.model()->data(index, Qt::DisplayRole).toString();
			if (currentText != ""){
				UnitList *unitlist = new UnitList();
				QStringList list = unitlist->getUnitList(currentText);
				editor->clear();
				foreach(QString unit, list)
					editor->addItem(unit);
				for(int i = 0; i < editor->count(); i++)
					if (currentText == editor->itemText(i)){
						editor->setCurrentIndex(i);
						break;
					}
			}else editor->setEnabled(false);
			return editor;
		}else{
			QPushButton *button = new QPushButton(parent);
			button->setText(index.model()->data(index, Qt::DisplayRole).toString());
			//QString a = getIndex(index, DATA).data().toString();
			//string_data = a;
			//emit data("D");
			connect(button, SIGNAL(clicked()), this, SLOT(paremeterEditorShow()));
			return button;
		}
	}
	return NULL;
}
 
void Delegate::setEditorData(QWidget *editor, const QModelIndex &index) const{
	if (index.column() == 1) {
		QModelIndex indexLC(index);
		indexLC.c = 3;
		int type = indexLC.model()->data(indexLC, Qt::DisplayRole).toInt();
		QVariant val = index.model()->data(index, Qt::DisplayRole);
		if (type == 0 || type == 4){
			QComboBox *comboEditor = qobject_cast<QComboBox *>(editor);
		} else if (type == 1){
			QDoubleSpinBox *valueEditor = qobject_cast<QDoubleSpinBox *>(editor);
			valueEditor->setValue(index.model()->data(index, Qt::EditRole).toDouble());
		}else if (type == 2){
			QLineEdit *textEditor = qobject_cast<QLineEdit *>(editor);
			textEditor->setText(index.model()->data(index, Qt::EditRole).toString());
		}
	}else{
		QModelIndex indexUnit(index);
		indexUnit.c = 2;
		if(indexUnit.data().toInt() != 5){
		QComboBox *comboEditor = qobject_cast<QComboBox *>(editor);
		if (comboEditor) {
			QString currentText = comboEditor->currentText();
			UnitList *unitlist = new UnitList();
			QStringList list = unitlist->getUnitList(currentText);
			comboEditor->clear();
			foreach(QString unit, list)
				comboEditor->addItem(unit);
				
			for(int i = 0; i < comboEditor->count(); i++)
				if (currentText == comboEditor->itemText(i)){
					comboEditor->setCurrentIndex(i);
					break;
				}
			comboEditor->setEnabled(comboEditor->count() > 1);
		}
		}else{
			QPushButton *button = new QPushButton(editor);
		}
	}
}

void Delegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const{
	if (index.column() == 1) {
		int type = getIndex(index, TYPE).data(Qt::DisplayRole).toInt();
		QVariant val = index.data(Qt::DisplayRole);
		if (type == 0 || type == 4){
			QComboBox *comboEditor = qobject_cast<QComboBox *>(editor);
			model->setData(index, comboEditor->currentText());
			if (type == 4){

				QString cur_item = index.data(Qt::DisplayRole).toString();
				QStringList list = getIndex(index, DATA).data(Qt::DisplayRole).toString().split(";");
				model->setData(getIndex(index, DATA), getComboboxDataString(cur_item, list));
			}
		} else if (type == 1){
			QDoubleSpinBox *valueEditor = qobject_cast<QDoubleSpinBox *>(editor);
			model->setData(index, valueEditor->value());
		}else if (type == 2){
			QLineEdit *textEditor = qobject_cast<QLineEdit *>(editor);
			model->setData(index, textEditor->text());
		}
	}else{
		QComboBox *comboEditor = qobject_cast<QComboBox *>(editor);
		if (comboEditor) {
			model->setData(index, comboEditor->currentText());
		}
	}
}

void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const{
	painter->save();
	QPen pen(Qt::lightGray);
	pen.setWidth(1);
	painter->setPen(pen);
	QRect rc(option.rect);
	painter->drawLine(QLine(rc.right(), rc.top(), rc.right(), rc.bottom()));
	painter->drawLine(QLine(0, rc.bottom(), rc.right(), rc.bottom()));
	painter->restore();
	QItemDelegate::paint(painter, option, index);
}


QString getComboboxDataString(QString cur_item, QStringList list){
	QString str;
	for (int i = 1; i < list.count(); i++)
		if (cur_item == list[i]){
			str = QString::number(i - 1);
			break;
		}
		if (str == "") str = "0";
		for (int i = 1; i < list.count(); i++)
			str += ";" + list[i];
	return str;
}

void Delegate::paremeterEditorShow(){
	Editor editor(new QWidget());

	editor.setData(getIndex(main->properties->currentIndex(), NAME).data().toString(),
		getIndex(main->properties->currentIndex(), DATA).data().toString());
	if (editor.exec()){
		QString data = editor.getData();
		QString count = QString::number(data.split("/").back().split(";").count());
		if (data.split("/").back() == "") count = "0";
		main->properties->model()->setData(getIndex(main->properties->currentIndex(), VALUE), "count: " + count);
		main->properties->model()->setData(getIndex(main->properties->currentIndex(), DATA), data);
	}
}

